﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HtmlAgilityPack;
using HtmlDoc = HtmlAgilityPack.HtmlDocument;
using System.Linq;
using System.Net;
using Newtonsoft.Json.Linq;
using System.Xml.Linq;

namespace SearchApp
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            // 创新点：添加相似度对比功能
            lblSimilarity.Text = "相似度：0%";
        }

        // 创新点：支持超时设置
        private readonly TimeSpan timeout = TimeSpan.FromSeconds(10);
        private HttpClient client = new HttpClient();
        private readonly string BaiduApiKey = "YOUR_Baidu_API_KEY"; // 替换为你的Baidu API密钥
        private readonly string BaiduSearchEngineId = "YOUR_SEARCH_ENGINE_ID"; // 替换为你的搜索引擎ID

        private async void btnSearch_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtKeyword.Text))
            {
                MessageBox.Show("请输入搜索关键字");
                return;
            }

            btnSearch.Enabled = false;
            lblStatus.Text = "搜索中...";
            lblSimilarity.Text = "相似度：计算中...";

            try
            {
                // 使用CancellationToken实现超时控制
                var cts = new CancellationTokenSource(timeout);

                // 并行执行多个搜索引擎搜索
                var BaiduTask = SearchBaiduAsync(txtKeyword.Text, cts.Token);
                var bingTask = SearchBingAsync(txtKeyword.Text, cts.Token);

                await Task.WhenAll(BaiduTask, bingTask);

                txtBaidu.Text = BaiduTask.Result; // 将Baidu结果显示在Baidu的文本框中
                txtBing.Text = bingTask.Result;

                // 创新点：计算并显示结果相似度
                var similarity = CalculateSimilarity(txtBaidu.Text, txtBing.Text);
                lblSimilarity.Text = $"相似度：{similarity}%";
            }
            catch (TaskCanceledException)
            {
                MessageBox.Show("请求超时，请检查网络连接");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"发生错误：{ex.Message}");
            }
            finally
            {
                btnSearch.Enabled = true;
                lblStatus.Text = "就绪";
            }
        }

        private async Task<string> SearchBaiduAsync(string keyword, CancellationToken ct)
        {
            try
            {
                var encodedKeyword = Uri.EscapeDataString(keyword);
                var url = $"https://www.baidu.com/s?wd={encodedKeyword}";

                // 设置浏览器User-Agent绕过反爬机制
                client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");

                var response = await client.GetAsync(url, ct);
                var content = await response.Content.ReadAsStringAsync();
                return ParseBaiduResults(content);
            }
            catch (Exception ex)
            {
                return $"百度搜索结果获取失败：{ex.Message}";
            }
        }

        private async Task<string> SearchBingAsync(string keyword, CancellationToken ct)
        {
            try
            {
                var encodedKeyword = Uri.EscapeDataString(keyword);
                var url = $"https://www.bing.com/search?q={encodedKeyword}";

                var response = await client.GetAsync(url, ct);
                var content = await response.Content.ReadAsStringAsync();
                return ParseBingResults(content);
            }
            catch (Exception ex)
            {
                return $"必应搜索结果获取失败：{ex.Message}";
            }
        }

        private string ParseBaiduResults(string json)
        {
            try
            {
                var jsonObject = JObject.Parse(json);
                var items = jsonObject["items"] as JArray;

                if (items == null || items.Count == 0)
                    return "未找到有效结果";

                var result = new List<string>();
                foreach (var item in items)
                {
                    var snippet = item["snippet"].ToString();
                    if (!string.IsNullOrEmpty(snippet))
                        result.Add(snippet);
                }

                return TruncateText(string.Join(" ", result), 200);
            }
            catch (Exception ex)
            {
                return $"解析Baidu搜索结果失败：{ex.Message}";
            }
        }

        private string ParseBingResults(string html)
        {
            var doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);

            // 使用XPath定位必应搜索结果摘要
            var nodes = doc.DocumentNode.SelectNodes("//div[contains(@class, 'b_caption')]//p");
            if (nodes == null) return "未找到有效结果";

            var result = string.Join(" ", nodes.Select(n => n.InnerText.CleanHtmlText()));
            return TruncateText(result, 200);
        }

        private string TruncateText(string text, int maxLength)
        {
            return text.Length > maxLength ? text.Substring(0, maxLength) + "..." : text;
        }

        // 创新点：使用Jaccard相似度算法计算结果相似度
        private double CalculateSimilarity(string text1, string text2)
        {
            if (string.IsNullOrEmpty(text1) || string.IsNullOrEmpty(text2))
                return 0;

            var set1 = new HashSet<string>(text1.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
            var set2 = new HashSet<string>(text2.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));

            var intersection = set1.Intersect(set2).Count();
            var union = set1.Union(set2).Count();

             return union == 0 ? 0 : Math.Round(intersection * 100.0 / union, 2);
        }
    }

    // 扩展方法：清理HTML文本
    public static class StringExtensions
    {
        public static string CleanHtmlText(this string input)
        {
            return WebUtility.HtmlDecode(input)
                .Replace("\n", "")
                .Replace("\r", "")
                .Replace("\t", "")
                .Trim();
        }
    }
}
